package com.hqyj.onlineExamination.modules.account.service.impl;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.hqyj.onlineExamination.modules.account.dao.UserDao;
import com.hqyj.onlineExamination.modules.account.dao.UserRoleDao;
import com.hqyj.onlineExamination.modules.account.entity.User;
import com.hqyj.onlineExamination.modules.account.entity.UserRole;
import com.hqyj.onlineExamination.modules.account.service.UserService;
import com.hqyj.onlineExamination.modules.common.entity.ResultEntity;
import com.hqyj.onlineExamination.modules.common.entity.SearchBean;
import com.hqyj.onlineExamination.util.MD5Util;
import com.hqyj.onlineExamination.util.RedisUtils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.Subject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import javax.transaction.Transactional;
import java.time.LocalDateTime;
import java.util.Collections;
import java.util.List;
import java.util.Optional;

@Service
public class UserServiceImpl implements UserService {

    private final static Logger LOGGER = LoggerFactory.getLogger(UserServiceImpl.class);

    @Autowired
    private UserDao userDao;
    @Autowired
    private UserRoleDao userRoleDao;
    @Autowired
    private RedisUtils redisUtils;
    @Autowired
    private HttpServletRequest request;

    @Override
    public User getUserByUserNameAndPassword(String userName, String password) {
        return userDao.getUserByUserNameAndPassword(userName, MD5Util.getMD5(password));
    }

    @Override
    public User getUserByUserName(String userName) {
        List<User> users = Optional
                .ofNullable(userDao.getUserByUserName(userName))
                .orElse(Collections.emptyList());
        return users.isEmpty() ? new User() : users.get(0);
    }

    @Override
    public ResultEntity<User> login(User user) {
        // 根据登录次数判断账号是否为锁定状态
//        Integer LOGIN_FAIL_MAX_COUNT = 5;
//        String key = String.format("login_fail_count_%s", user.getUserName());
//        int loginFailCount = redisUtils.get(key) == null ? 0 : (int) redisUtils.get(key);;
//        if (loginFailCount >= LOGIN_FAIL_MAX_COUNT){
//            // 设置key多少秒失效，即锁定时间。
//            redisUtils.expire(key,30);
//            return new ResultEntity<>(ResultEntity.ResultStatus.FAILED.status,
//                    String.format("该账号连续 %d 次登录失败，锁定账号 30 秒。 ", loginFailCount));
//        }

        //获取subject
        Subject subject = SecurityUtils.getSubject();
        //包装令牌
        UsernamePasswordToken usernamePasswordToken =
                new UsernamePasswordToken(user.getUserName(),
                        MD5Util.getMD5(user.getPassword()));

        try {
            subject.login(usernamePasswordToken);
            subject.checkRoles();

            //将登录的用户的信息存入session
            Session session = subject.getSession();
            //subject.getPrincipal()身份认证器里包装的
            session.setAttribute("user", subject.getPrincipal());
        } catch (Exception e) {
            e.printStackTrace();
            LOGGER.debug(e.getMessage());

            // 登录失败，增加锁定次数。
//            if (loginFailCount < LOGIN_FAIL_MAX_COUNT){
//                redisUtils.increment(key,1);
//                loginFailCount += 1;
//                return new ResultEntity<>(ResultEntity.ResultStatus.FAILED.status,
//                        String.format("登录失败 %d 次，还剩 %d 次。", loginFailCount, (LOGIN_FAIL_MAX_COUNT - loginFailCount)));
//            }
//            return new ResultEntity<>(
//                    ResultEntity.ResultStatus.FAILED.status, "登录失败");
        }
        return new ResultEntity<>(
                ResultEntity.ResultStatus.SUCCESS.status, "Login success.");
    }


    @Override
    public void logout() {
        Subject subject = SecurityUtils.getSubject();
        subject.logout();
    }

    @Override
    @Transactional
    public ResultEntity<User> insertUser(User user) {
        List<User> users = Optional
                .ofNullable(userDao.getUserByUserNameOrEmail(user.getEmail(), user.getUserName()))
                .orElse(Collections.emptyList());
        if (users.size() > 0) {
            return new ResultEntity<User>(ResultEntity.ResultStatus.FAILED.status, "User Name or email is repeat.");
        }

        user.setCreateDate(LocalDateTime.now());
        user.setPassword(MD5Util.getMD5(user.getPassword()));
        userDao.insertUser(user);
        if (user.getRoles() != null) {
            user.getRoles().stream()
                    .forEach(item -> {userRoleDao.insertUserRole(new UserRole(user.getId(), item.getId()));});
        }
        return new ResultEntity<User>(ResultEntity.ResultStatus.SUCCESS.status, "Insert success", user);
    }

    @Override
    @Transactional
    public ResultEntity<User> updateUser(User user) {
        List<User> users = Optional
                .ofNullable(userDao.getUserByUserNameOrEmail(user.getEmail(), user.getUserName()))
                .orElse(Collections.emptyList());
        if (users.stream().filter(item -> item.getId() != user.getId()).count() > 0) {
            return new ResultEntity<User>(ResultEntity.ResultStatus.FAILED.status, "User Name or email is repeat.");
        }

        userDao.updateUser(user);
        HttpSession session = request.getSession();
        List<User> user1 = userDao.getUserByUserName(user.getUserName());
        session.setAttribute("user",user1.get(0));
        if (user.getRoles() != null && !user.getRoles().isEmpty()) {
            userRoleDao.deleteUserRoleByUserId(user.getId());
            user.getRoles().stream()
                    .forEach(item -> {userRoleDao.insertUserRole(new UserRole(user.getId(), item.getId()));});
        }

        return new ResultEntity<User>(ResultEntity.ResultStatus.SUCCESS.status, "Update success", user);
    }

    @Override
    public User getUserById(int id) {
        return userDao.getUserById(id);
    }

    @Override
    @Transactional
    public ResultEntity<Object> deleteUserById(int id) {
        userDao.deleteUserById(id);
        userRoleDao.deleteUserRoleByUserId(id);
        return new ResultEntity<Object>(ResultEntity.ResultStatus.SUCCESS.status, "Delete success");
    }

    @Override
    public PageInfo<User> getUsersBySearchBean(SearchBean searchBean) {
        searchBean.initSearchBean();
        PageHelper.startPage(searchBean.getCurrentPage(), searchBean.getPageSize());
        return new PageInfo<User>(Optional
                .ofNullable(userDao.getUsersBySearchVo(searchBean))
                .orElse(Collections.emptyList()));
    }

    public List<User> getUsers() {
        return userDao.getUsers();
    }
}
